package com.example.smartagrisys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.smartagrisys.dto.FertilizingRecordDTO;
import com.example.smartagrisys.entity.FertilizingRecord;
import com.example.smartagrisys.entity.Land;
import com.example.smartagrisys.entity.User;
import com.example.smartagrisys.exception.BusinessException;
import com.example.smartagrisys.mapper.FertilizingRecordMapper;
import com.example.smartagrisys.mapper.LandMapper;
import com.example.smartagrisys.service.FertilizingRecordService;
import com.example.smartagrisys.service.InventoryService;
import com.example.smartagrisys.service.UserService;
import com.example.smartagrisys.vo.FertilizingRecordVO;
import com.example.smartagrisys.vo.InventoryVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 施肥记录服务实现类
 */
@Slf4j
@Service
public class FertilizingRecordServiceImpl extends ServiceImpl<FertilizingRecordMapper, FertilizingRecord> implements FertilizingRecordService {

    @Resource
    private LandMapper landMapper;

    @Resource
    private UserService userService;

    @Resource
    private InventoryService inventoryService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long add(FertilizingRecordDTO dto, Long farmerId) {
        // 检查农户
        User farmer = checkFarmerUser(farmerId);

        // 检查地块
        Land land = checkLand(dto.getLandId(), farmerId);

        // 检查肥料（使用库存ID直接检查）
        InventoryVO fertilizer = inventoryService.getInventoryById(dto.getFertilizerId());
        if (fertilizer == null) {
            log.error("肥料不存在，ID: {}", dto.getFertilizerId());
            throw new BusinessException("肥料不存在");
        }
        
        // 如果类型不是肥料，抛出异常
        if (!"肥料".equals(fertilizer.getType())) {
            log.error("物品不是肥料，ID: {}, 类型: {}", dto.getFertilizerId(), fertilizer.getType());
            throw new BusinessException("所选物品不是肥料");
        }
        
        log.info("找到肥料: {}, 库存: {}{}", fertilizer.getName(), fertilizer.getQuantity(), fertilizer.getUnit());

        // 更新库存（减少数量）
        boolean updated = inventoryService.reduceInventoryDirectly(dto.getFertilizerId(), farmerId, dto.getAmount());
        if (!updated) {
            log.error("肥料库存不足，ID: {}, 需要: {}, 库存: {}", dto.getFertilizerId(), dto.getAmount(), fertilizer.getQuantity());
            throw new BusinessException("肥料库存不足");
        }
        
        log.info("成功扣减农户 {} 的肥料库存，肥料: {}, 数量: {}", farmerId, fertilizer.getName(), dto.getAmount());

        // 创建施肥记录
        FertilizingRecord record = new FertilizingRecord();
        record.setFarmerId(farmerId);
        record.setLandId(dto.getLandId());
        record.setCropType(dto.getCropType());
        record.setFertilizerId(dto.getFertilizerId());
        record.setDate(dto.getDate());
        record.setAmount(dto.getAmount());
        record.setNote(dto.getNote());

        // 保存记录
        boolean saved = save(record);
        if (!saved) {
            throw new BusinessException("添加施肥记录失败");
        }

        return record.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(FertilizingRecordDTO dto, Long farmerId) {
        // 检查记录是否存在且属于当前农户
        FertilizingRecord existingRecord = getById(dto.getId());
        if (existingRecord == null || !existingRecord.getFarmerId().equals(farmerId)) {
            throw new BusinessException("施肥记录不存在或不属于当前用户");
        }

        // 检查农户
        User farmer = checkFarmerUser(farmerId);

        // 检查地块
        Land land = checkLand(dto.getLandId(), farmerId);

        // 检查肥料（使用库存ID直接检查）
        InventoryVO fertilizer = inventoryService.getInventoryById(dto.getFertilizerId());
        if (fertilizer == null) {
            log.error("肥料不存在，ID: {}", dto.getFertilizerId());
            throw new BusinessException("肥料不存在");
        }
        
        // 如果类型不是肥料，抛出异常
        if (!"肥料".equals(fertilizer.getType())) {
            log.error("物品不是肥料，ID: {}, 类型: {}", dto.getFertilizerId(), fertilizer.getType());
            throw new BusinessException("所选物品不是肥料");
        }

        // 如果肥料或用量变更，需要调整库存
        if (!existingRecord.getFertilizerId().equals(dto.getFertilizerId()) || 
            existingRecord.getAmount().compareTo(dto.getAmount()) != 0) {
            
            // 1. 先将原来的肥料归还库存
            boolean returned = inventoryService.reduceInventoryDirectly(
                existingRecord.getFertilizerId(), 
                farmerId, 
                existingRecord.getAmount().negate()  // 使用负数来增加库存
            );
            
            if (!returned) {
                log.error("归还原有肥料库存失败，ID: {}, 数量: {}", existingRecord.getFertilizerId(), existingRecord.getAmount());
                throw new BusinessException("更新肥料库存失败");
            }
            
            // 2. 再从新肥料中扣减库存
            boolean deducted = inventoryService.reduceInventoryDirectly(dto.getFertilizerId(), farmerId, dto.getAmount());
            if (!deducted) {
                // 如果扣减失败，需要回滚之前的归还操作
                inventoryService.reduceInventoryDirectly(
                    existingRecord.getFertilizerId(), 
                    farmerId, 
                    existingRecord.getAmount()
                );
                log.error("新肥料库存不足，ID: {}, 需要: {}", dto.getFertilizerId(), dto.getAmount());
                throw new BusinessException("新肥料库存不足");
            }
        }

        // 更新记录
        existingRecord.setLandId(dto.getLandId());
        existingRecord.setCropType(dto.getCropType());
        existingRecord.setFertilizerId(dto.getFertilizerId());
        existingRecord.setDate(dto.getDate());
        existingRecord.setAmount(dto.getAmount());
        existingRecord.setNote(dto.getNote());

        return updateById(existingRecord);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Long id, Long farmerId) {
        // 检查记录是否存在且属于当前农户
        FertilizingRecord record = getById(id);
        if (record == null || !record.getFarmerId().equals(farmerId)) {
            throw new BusinessException("施肥记录不存在或不属于当前用户");
        }

        // 删除记录之前，需要归还库存
        boolean returned = inventoryService.reduceInventoryDirectly(
            record.getFertilizerId(), 
            farmerId, 
            record.getAmount().negate()  // 使用负数来增加库存
        );
        
        if (!returned) {
            log.error("归还肥料库存失败，ID: {}, 数量: {}", record.getFertilizerId(), record.getAmount());
            throw new BusinessException("归还肥料库存失败");
        }

        return removeById(id);
    }

    @Override
    public FertilizingRecordVO getDetail(Long id) {
        FertilizingRecord record = getById(id);
        if (record == null) {
            throw new BusinessException("施肥记录不存在");
        }
        return convertToVO(record);
    }

    @Override
    public Page<FertilizingRecordVO> getFarmerFertilizingRecords(Long farmerId, Integer pageNum, Integer pageSize) {
        Page<FertilizingRecord> page = new Page<>(pageNum, pageSize);
        
        // 查询数据
        LambdaQueryWrapper<FertilizingRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FertilizingRecord::getFarmerId, farmerId)
               .orderByDesc(FertilizingRecord::getCreateTime);
        
        Page<FertilizingRecord> recordPage = page(page, wrapper);
        
        // 转换结果
        Page<FertilizingRecordVO> voPage = new Page<>();
        BeanUtils.copyProperties(recordPage, voPage, "records");
        
        if (!CollectionUtils.isEmpty(recordPage.getRecords())) {
            // 提取ID列表
            List<Long> landIds = recordPage.getRecords().stream()
                                         .map(FertilizingRecord::getLandId)
                                         .distinct()
                                         .collect(Collectors.toList());
            
            List<Long> fertilizerIds = recordPage.getRecords().stream()
                                              .map(FertilizingRecord::getFertilizerId)
                                              .distinct()
                                              .collect(Collectors.toList());
            
            // 批量加载关联数据
            Map<Long, Land> landMap = loadLands(landIds);
            Map<Long, InventoryVO> fertilizerMap = loadInventoryFertilizers(fertilizerIds);
            
            // 转换为VO
            List<FertilizingRecordVO> voList = recordPage.getRecords().stream()
                                                     .map(record -> convertToVO(record, landMap, fertilizerMap))
                                                     .collect(Collectors.toList());
            
            voPage.setRecords(voList);
        } else {
            voPage.setRecords(Collections.emptyList());
        }
        
        return voPage;
    }

    @Override
    public List<FertilizingRecordVO> getFarmerAllFertilizingRecords(Long farmerId) {
        // 查询数据
        LambdaQueryWrapper<FertilizingRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FertilizingRecord::getFarmerId, farmerId)
               .orderByDesc(FertilizingRecord::getCreateTime);
        
        List<FertilizingRecord> records = list(wrapper);
        
        if (CollectionUtils.isEmpty(records)) {
            return Collections.emptyList();
        }
        
        // 提取ID列表
        List<Long> landIds = records.stream()
                                  .map(FertilizingRecord::getLandId)
                                  .distinct()
                                  .collect(Collectors.toList());
        
        List<Long> fertilizerIds = records.stream()
                                       .map(FertilizingRecord::getFertilizerId)
                                       .distinct()
                                       .collect(Collectors.toList());
        
        // 批量加载关联数据
        Map<Long, Land> landMap = loadLands(landIds);
        Map<Long, InventoryVO> fertilizerMap = loadInventoryFertilizers(fertilizerIds);
        
        // 转换为VO
        return records.stream()
                    .map(record -> convertToVO(record, landMap, fertilizerMap))
                    .collect(Collectors.toList());
    }

    /**
     * 转换为VO对象（单独加载关联数据）
     */
    private FertilizingRecordVO convertToVO(FertilizingRecord record) {
        FertilizingRecordVO vo = new FertilizingRecordVO();
        BeanUtils.copyProperties(record, vo);
        
        // 获取地块信息
        try {
            Land land = landMapper.selectById(record.getLandId());
            if (land != null) {
                vo.setLandName(land.getName());
                vo.setLandLocation(land.getLocation());
            }
        } catch (Exception e) {
            log.error("获取地块信息出错，地块ID: {}", record.getLandId(), e);
        }
        
        // 获取肥料信息
        try {
            InventoryVO fertilizer = inventoryService.getInventoryById(record.getFertilizerId());
            if (fertilizer != null) {
                vo.setFertilizerName(fertilizer.getName());
                vo.setFertilizerType(fertilizer.getType());
                vo.setUnit(fertilizer.getUnit());
            }
        } catch (Exception e) {
            log.error("获取肥料信息出错，肥料ID: {}", record.getFertilizerId(), e);
        }
        
        return vo;
    }

    /**
     * 转换为VO对象（使用预加载的关联数据）
     */
    private FertilizingRecordVO convertToVO(FertilizingRecord record, Map<Long, Land> landMap, Map<Long, InventoryVO> inventoryMap) {
        FertilizingRecordVO vo = new FertilizingRecordVO();
        BeanUtils.copyProperties(record, vo);
        
        // 设置地块信息
        if (landMap.containsKey(record.getLandId())) {
            Land land = landMap.get(record.getLandId());
            vo.setLandName(land.getName());
            vo.setLandLocation(land.getLocation());
        }
        
        // 设置肥料信息
        if (inventoryMap.containsKey(record.getFertilizerId())) {
            InventoryVO fertilizer = inventoryMap.get(record.getFertilizerId());
            vo.setFertilizerName(fertilizer.getName());
            vo.setFertilizerType(fertilizer.getType());
            vo.setUnit(fertilizer.getUnit());
        }
        
        return vo;
    }

    /**
     * 批量加载地块信息
     */
    private Map<Long, Land> loadLands(List<Long> landIds) {
        if (CollectionUtils.isEmpty(landIds)) {
            return Collections.emptyMap();
        }
        
        try {
            LambdaQueryWrapper<Land> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(Land::getId, landIds);
            
            List<Land> lands = landMapper.selectList(wrapper);
            if (CollectionUtils.isEmpty(lands)) {
                return Collections.emptyMap();
            }
            
            return lands.stream().collect(Collectors.toMap(Land::getId, Function.identity(), (a, b) -> a));
        } catch (Exception e) {
            log.error("批量加载地块信息出错", e);
            return Collections.emptyMap();
        }
    }

    /**
     * 批量加载肥料库存信息
     */
    private Map<Long, InventoryVO> loadInventoryFertilizers(List<Long> inventoryIds) {
        if (CollectionUtils.isEmpty(inventoryIds)) {
            return Collections.emptyMap();
        }
        
        Map<Long, InventoryVO> result = new HashMap<>();
        
        try {
            for (Long id : inventoryIds) {
                InventoryVO inventory = inventoryService.getInventoryById(id);
                if (inventory != null) {
                    result.put(id, inventory);
                }
            }
        } catch (Exception e) {
            log.error("批量加载库存信息出错", e);
        }
        
        return result;
    }

    /**
     * 检查农户用户是否存在
     */
    private User checkFarmerUser(Long userId) {
        User user = userService.getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        if (!"farmer".equals(user.getRole())) {
            throw new BusinessException("只有农户才能进行施肥操作");
        }
        
        return user;
    }

    /**
     * 检查地块是否存在且属于当前农户
     */
    private Land checkLand(Long landId, Long farmerId) {
        Land land = landMapper.selectById(landId);
        if (land == null) {
            throw new BusinessException("地块不存在");
        }
        
        if (!land.getFarmerId().equals(farmerId)) {
            throw new BusinessException("地块不属于当前用户");
        }
        
        return land;
    }
} 